import { IAppMenuStore } from '@/core/interface/widgets/store';
import { CtrlController } from './ctrl-controller';
import {
	AppMenuActionType,
	IAppFunc,
	IAppMenuAbility,
	IAppMenuController,
	IAppMenuControllerParams,
	IAppMenuModel,
	ICtrlActionResult,
	IParam,
} from '../../interface';
import { deepCopy } from '@/core';
import { router } from '@/router';
import { useAppStoreWithOut } from '@/store';
import { getIndexRoutePath } from '@/utils';

/**
 * 菜单部件控制器  (todo:视图/部件交互方式存在问题)
 *
 * @export
 * @class MenuController
 * @extends {CtrlController<AppMenuActionType, IAppMenuStore, IAppMenuAbility>}
 * @implements {IMenuController}
 * @template T
 */
export class AppMenuController
	extends CtrlController<AppMenuActionType, IAppMenuStore, IAppMenuAbility>
	implements IAppMenuController<IAppMenuStore, IAppMenuAbility>
{
	/**
	 * @description 是否应用起始页
	 * @protected
	 * @type {boolean}
	 * @memberof AppMenuController
	 */
	protected isDefaultPage!: boolean;

	/**
	 * @description 空白首页模式
	 * @protected
	 * @type {boolean}
	 * @memberof AppMenuController
	 */
	protected isBlankMode!: boolean;

	/**
	 * @description 默认视图
	 * @protected
	 * @type {string}
	 * @memberof AppMenuController
	 */
	protected defPSAppView?: string;

	/**
	 * @description 菜单模式
	 * @protected
	 * @type {string}
	 * @memberof AppMenuController
	 */
	protected mode!: string;

	/**
	 * @description 菜单模式
	 * @protected
	 * @type {string}
	 * @memberof AppMenuController
	 */
	protected cacheMenu!: IParam[];

	/**
	 * Creates an instance of AppMenuController.
	 * @param {IAppMenuControllerParams} params
	 * @memberof AppMenuController
	 */
	public constructor(
		params: IAppMenuControllerParams<AppMenuActionType, IAppMenuAbility>
	) {
		super(params);
		this.ctrlInit(params);
	}

	/**
	 * 处理部件初始化
	 *
	 * @protected
	 * @param {IAppMenuControllerParams<AppMenuActionType, IAppMenuAbility>} params
	 * @memberof AppMenuController
	 */
	protected processCtrlInit(
		params: IAppMenuControllerParams<AppMenuActionType, IAppMenuAbility>
	) {
		super.processCtrlInit(params);
		this.isDefaultPage = params.isDefaultPage === true;
		this.isBlankMode = params.isBlankMode === true;
		this.defPSAppView = params.defPSAppView;
		this.mode = params.mode;
		const model = this.getModel<IAppMenuModel>();
		Object.assign(this.store, {
			defaultExpands: model.defaultExpands,
			menus: deepCopy(model.menus),
			selections: [],
		});
	}

	/**
	 * 获取数据
	 *
	 * @return {*}  {IParam[]}
	 * @memberof AppMenuController
	 */
	public getData(): IParam[] {
		const data: Array<IParam> = this.store.menus;
		return data;
	}

	/**
	 * @description 获取能力
	 * @return {*}  {IAppMenuAbility}
	 * @memberof AppMenuController
	 */
	public getAbility(): IAppMenuAbility {
		return {
			...super.getAbility(),
			load: this.load.bind(this),
		};
	}

	/**
	 * @description 加载数据
	 * @memberof AppMenuController
	 */
	public load(): Promise<ICtrlActionResult> {
		const menus: IParam[] = deepCopy(this.model.menus) as IParam[];
		if (App.getEnableAppPermission()) {
			this.computedMenusResource(this.store.menus);
		} else {
			this.store.menus = menus;
		}
		this.computeMenusIcon();
		this.computeDefaultView();
		this.emit('loaded', this.store.menus);
		this.cacheMenu = this.getData();
		return Promise.resolve({ ok: false, data: this.getData(), rowData: menus });
	}

	/**
	 * @description 设置选中数据
	 * @param {IParam} menu
	 * @memberof AppMenuController
	 */
	public setSelection(menu: IParam) {
		this.store.selections = [menu.name];
		this.store.defaultExpands.push(menu.name);
	}

	/**
	 * @description 计算菜单权限
	 * @memberof AppMenuController
	 */
	protected computedMenusResource(menus: IParam[]) {
		if (menus.length > 0) {
			const appName = App.getAppConfig().appName;
			const sysName = App.getAppConfig().sysName;
			const menuPermissionMode =
				App.getProjectSetting().menuSetting.menuPermissionMode;
			menus.forEach((menu: IParam) => {
				const tag: string = Object.is(menuPermissionMode, 'RT')
					? `${appName}-${this.model.codeName}-${menu.name}`
					: menu.resourceTag
					? menu.resourceTag
					: `${sysName}-${appName}-${this.model.codeName}-${menu.name}`;
				if (tag && !App.getAppMenuAuth(tag)) {
					menu.hidden = true;
				}
				if (menu.menuItems && menu.menuItems.length > 0) {
					this.computedMenusResource(menu.menuItems);
				}
			});
		}
	}

	/**
	 * @description 计算第一级菜单图标
	 * @memberof AppMenuController
	 */
	public computeMenusIcon() {
		this.store.menus.forEach((menu: IParam) => {
			if (!menu.iconClass && !menu.imgPath && !menu.imgPathX) {
				menu.iconClass = 'fa fa-cogs';
			}
		});
	}

	/**
	 * @description 设置默认视图
	 * @param {IParam[]} menus
	 * @return {*}
	 * @memberof AppMenuController
	 */
	public setDefaultView(menus: IParam[]) {
		const appFuncConfig = App.getAppFuncConfig();
		const result = menus.some((menu: any) => {
			if (menu.funcTag && menu.openDefault && !menu.hidden) {
				const appFunc = appFuncConfig?.find((_appFunc: any) =>
					Object.is(_appFunc.funcTag, menu.funcTag)
				);
				if (appFunc && appFunc.openViewCodeName) {
					const {
						setDefaultViewCodeName,
						unshiftBreadcrumbs,
						getBreadcrumbs,
						addBreadcrumbs,
					} = useAppStoreWithOut();
					setDefaultViewCodeName(appFunc.openViewCodeName);
					const appViewConfig = App.getAppViewConfig();
					const view = appViewConfig[appFunc.openViewCodeName];
					if (view) {
						if (
							getBreadcrumbs.length === 1 &&
							!Object.is(getBreadcrumbs[0].tag, appFunc.openViewCodeName)
						) {
							const context = deepCopy(this.store.context);
							Object.assign(view, { isRoute: true, context });
							unshiftBreadcrumbs(view);
							const currentRoute = unref(router.currentRoute);
							if (
								currentRoute.meta &&
								!currentRoute.meta.ignoreAddPage &&
								currentRoute.meta.tag !== 'AppWFRedirectView'
							) {
								const pageMeta: any = {
									...currentRoute.meta,
									fullPath: currentRoute.fullPath,
								};
								addBreadcrumbs(pageMeta);
							}
						}
					}
					return true;
				}
			}
			if (menu.menuItems && menu.menuItems.length > 0) {
				return this.setDefaultView(menu.menuItems);
			}
			return false;
		});
		return result;
	}

	/**
	 * @description 计算默认视图
	 * @memberof AppMenuController
	 */
	public computeDefaultView() {
		if (!this.isDefaultPage || this.isBlankMode) {
			return;
		}
		const appFuncConfig = App.getAppFuncConfig();
		const currentRoute = unref(router.currentRoute);
		if (
			currentRoute &&
			currentRoute.matched &&
			currentRoute.matched.length == 2
		) {
			// 存在二级路由
			const [{}, matched] = currentRoute.matched;
			const appFunc: any = appFuncConfig.find(
				(_appFunc: any) =>
					Object.is(_appFunc.openViewCodeName, matched.meta.tag) &&
					Object.is(_appFunc.appFuncType, 'APPVIEW')
			);
			if (appFunc) {
				this.computeMenuSelect(this.store.menus, appFunc.funcTag);
			}
			this.setDefaultView(this.store.menus);
			return;
		} else if (this.defPSAppView) {
			// 存在默认视图
			const appFunc: any = appFuncConfig.find(
				(_appFunc: any) =>
					Object.is(_appFunc.openViewCodeName, this.defPSAppView) &&
					Object.is(_appFunc.appFuncType, 'APPVIEW')
			);
			if (appFunc) {
				this.computeMenuSelect(this.store.menus, appFunc.funcTag);
			}
			this.openDefaultView(this.defPSAppView);
			return;
		}
		this.computeMenuSelect(this.store.menus, '');
	}

	/**
	 * @description 计算菜单选中
	 * @param {IParam[]} menus
	 * @param {string} appFuncTag
	 * @return {*}  {boolean}
	 * @memberof AppMenuController
	 */
	public computeMenuSelect(menus: IParam[], appFuncTag: string): boolean {
		const appFuncConfig = App.getAppFuncConfig();
		const result = menus.some((menu: any) => {
			if (
				Object.is(appFuncTag, '') &&
				menu.funcTag &&
				menu.openDefault &&
				!menu.hidden
			) {
				const appFunc = appFuncConfig?.find((_appFunc: any) =>
					Object.is(_appFunc.funcTag, menu.funcTag)
				);
				if (appFunc && appFunc.openViewCodeName) {
					this.setSelection(menu);
					this.openDefaultView(
						appFunc.openViewCodeName,
						appFunc.navigateParam ? appFunc.navigateParam : {}
					);
					return true;
				}
			}
			if (menu.funcTag && Object.is(menu.funcTag, appFuncTag) && !menu.hidden) {
				this.setSelection(menu);
				return true;
			}
			if (menu.menuItems && menu.menuItems.length > 0) {
				return this.computeMenuSelect(menu.menuItems, appFuncTag);
			}
			return false;
		});
		return result;
	}

	/**
	 * @description 打开默认视图
	 * @param {string} codeName
	 * @memberof AppMenuController
	 */
	public openDefaultView(codeName: string, viewParam?: IParam) {
		const appViewConfig = App.getAppViewConfig();
		const view = appViewConfig[codeName];
		let localViewParam = {};
		if (viewParam) {
			localViewParam = Object.assign(localViewParam, viewParam);
		}
		if (view) {
			const { setDefaultViewCodeName } = useAppStoreWithOut();
			setDefaultViewCodeName(view.codeName);
			const context = deepCopy(this.store.context);
			App.getOpenViewHelper().openPage(view, context, localViewParam);
		} else {
			console.warn(App.ts('widget.common.nofindview', '未找到相关视图'));
		}
	}

	/**
	 * @description 处理菜单点击
	 * @param {number} index
	 * @memberof AppMenuController
	 */
	public handleMenuClick(name: string) {
		const item = this.computeItem(this.model.menus, name);
		if (!item || !item.name) {
			return;
		}
		if (item.funcTag) {
			const { removeBreadcrumbsFirst } = useAppStoreWithOut();
			removeBreadcrumbsFirst();
			if (
				Object.is(this.mode, 'TABEXP_LEFT') ||
				Object.is(this.mode, 'TABEXP_TOP') ||
				Object.is(this.mode, 'TABEXP_RIGHT') ||
				Object.is(this.mode, 'TABEXP_BOTTOM') ||
				Object.is(this.mode, 'TREEEXP')
			) {
				const appFuncConfig = App.getAppFuncConfig();
				if (appFuncConfig && appFuncConfig.length > 0) {
					const appFunc = appFuncConfig.find((appFunc: IAppFunc) =>
						Object.is(appFunc.funcTag, item.funcTag)
					);
					if (appFunc && appFunc.openViewCodeName) {
						this.store.openViewCodeName = appFunc.openViewCodeName;
					}
				}
			} else {
				App.getAppFuncHelper().execute(
					item.funcTag,
					this.store.context,
					this.store.viewParams
				);
			}
		} else {
			if (item.path) {
				const { currentRoute, push } = router;
				const indexPath = getIndexRoutePath(currentRoute.value);
				let path = `${indexPath}/${item.path}`;
				push({ path });
			} else {
				console.warn(App.ts('widget.menu.noconfigmenu'));
			}
		}
	}

	/**
	 * @description 计算当前菜单项
	 * @param {any[]} items
	 * @param {string} name
	 * @return {*}
	 * @memberof AppMenuController
	 */
	public computeItem(items: any[], name: string) {
		let item: any = null;
		if (items && items.length > 0) {
			items.some((_item: any) => {
				if (_item.name === name) {
					item = _item;
					return true;
				}
				const child = this.computeItem(_item.menuItems, name);
				if (child) {
					item = child;
					return true;
				}
				return false;
			});
		}
		return item;
	}

	/**
	 * 刷新
	 *
	 * @param {(IParam | undefined)} [args]
	 * @return {*}  {Promise<boolean>}
	 * @memberof CtrlController
	 */
	public refresh(args?: IParam | undefined): Promise<boolean> {
		if (!args?.value) {
			this.store.menus = this.cacheMenu;
			return Promise.resolve(true);
		}
		const { value } = args;
		const items = this.store.menus;
		const calcIndexOf = (filter: any[]): any => {
			let searchMenus: any[] = [];
			if (filter) {
				const filterMenus = (menus: any[], childrenArr: any[]) => {
					if (!menus.length) return;
					for (let menu of menus) {
						let children: any[] = [];
						if (menu.menuItems && menu.menuItems.length > 0) {
							filterMenus(menu.menuItems, children);
						}
						if (children.length > 0) {
							const filterMenu = Object.assign(deepCopy(menu), {
								menuItems: children,
							});
							childrenArr.push(filterMenu);
						} else if (menu.caption && menu.caption.search(filter) != -1) {
							const filterMenu = Object.assign(deepCopy(menu), {
								menuItems: [],
							});
							childrenArr.push(filterMenu);
						}
					}
				};
				filterMenus(this.cacheMenu, searchMenus);
			} else {
				searchMenus = this.cacheMenu;
			}
			return searchMenus;
		};
		const _items = calcIndexOf(value);
		this.store.menus = _items;
		return Promise.resolve(true);
	}
}
